

#include "fd_manager.h"
#include "Hook.h"

namespace zepco {


Fdctx::Fdctx(int fd) {
    init();
}

Fdctx::~Fdctx() {
    // TODO:
}

bool Fdctx::init() {
    if (m_isInit) {
        return true;
    }

    struct stat statbuf;
    if (-1 == fstat(m_fd, &statbuf)) {
        m_isInit = false;
        m_isSocket = false;
    } else {
        m_isInit = true;
        m_isSocket = S_ISSOCK(statbuf.st_mode);
    }

    if (m_isSocket) {
        int flags = fcntl_f(m_fd, F_GETFL, 0);
        if (!(flags & O_NONBLOCK)) {
            fcntl_f(m_fd, F_SETFL, flags | O_NONBLOCK);
        }
        m_sysNonBlock = true;
    } else {
        m_sysNonBlock = false;
    }

    return m_isInit;
}

void Fdctx::setTimeout(int type, uint64_t v) {
    // type == SO_RCVTIEMO or SO_SNDTIMEO
    if (type == SO_RCVTIMEO) {
        m_recvTimeout = v;
    } else {
        m_sendTimeout = v;
    }
}

uint64_t Fdctx::getTimeout(int type) {
    if (type == SO_RCVTIMEO) {
        return m_recvTimeout;
    } else {
        return m_sendTimeout;
    }
}

FdManager::FdManager() {
    m_datas.resize(64);
}

std::shared_ptr<Fdctx> FdManager::get(int fd, bool auto_create) {
    if (fd == -1)
        return nullptr;

    std::shared_lock<std::shared_mutex> read_lock(m_mtx);
#if 1
    if (m_datas.size() <= fd) {
        if (!auto_create) {
            return nullptr;
        }
    } else {
        if (m_datas[fd] || !auto_create) {
            return m_datas[fd];
        }
    }
#else

    if (!auto_create) {
        if (m_datas.size() <= fd) {
            return nullptr;
        } else if (m_datas[fd]) {
            return m_datas[fd];
        }
    }

#endif
    read_lock.unlock();

    // create fdctx
    std::unique_lock<std::shared_mutex> write_lock(m_mtx);

    if (m_datas.size() <= fd) {
        m_datas.resize(fd * 1.5);
    }

    m_datas[fd] = std::make_shared<Fdctx>(fd);
    return m_datas[fd];

}

void FdManager::del(int fd) {
    std::unique_lock<std::shared_mutex> write_lock(m_mtx);
    if (m_datas.size() <= fd) {
        return ;
    }
    m_datas[fd].reset();
}

}